import 'package:flutter/material.dart';

class AnimatedDecoratedRoute extends StatefulWidget {
  const AnimatedDecoratedRoute({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _AnimatedDecoratedRouteState();
}

class _AnimatedDecoratedRouteState extends State<AnimatedDecoratedRoute> {
  Color _decorationColor = Colors.blue;

  final _duration = const Duration(seconds: 1);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Animated Decorated'),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            const SizedBox(height: 20),
            AnimatedDecoratedBox1(
                decoration: BoxDecoration(color: _decorationColor),
                child: TextButton(
                  onPressed: () {
                    setState(() {
                      _decorationColor = Colors.red;
                    });
                  },
                  child: const Padding(
                    padding: EdgeInsets.all(20),
                    child: Text(
                      "AnimatedDecoratedBox",
                      style: TextStyle(color: Colors.white, fontSize: 28),
                    ),
                  ),
                ),
                duration: _duration)
          ],
        ),
      ),
    );
  }
}

class AnimatedDecoratedBox1 extends StatefulWidget {
  const AnimatedDecoratedBox1(
      {Key? key,
      required this.decoration,
      required this.child,
      required this.duration,
      this.curve = Curves.linear,
      this.reverseDuration})
      : super(key: key);

  final BoxDecoration decoration;

  final Widget child;

  final Duration duration;

  final Curve curve;

  final Duration? reverseDuration;

  @override
  State<StatefulWidget> createState() => _AnimatedDecoratedBox1State();
}

class _AnimatedDecoratedBox1State extends State<AnimatedDecoratedBox1>
    with SingleTickerProviderStateMixin {
  @protected
  AnimationController get controller => _controller;

  late AnimationController _controller;

  Animation<double> get animation => _animation;

  late Animation<double> _animation;

  late DecorationTween _tween;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: widget.duration,
      reverseDuration: widget.reverseDuration,
    );
    _tween = DecorationTween(begin: widget.decoration);
    _updateCurve();
  }

  void _updateCurve() {
    _animation = CurvedAnimation(parent: _controller, curve: widget.curve);
  }

  @override
  void didUpdateWidget(AnimatedDecoratedBox1 oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.curve != oldWidget.curve) _updateCurve();
    _controller.duration = widget.duration;
    _controller.reverseDuration = widget.reverseDuration;

    if (widget.decoration != (_tween.end ?? _tween.begin)) {
      _tween
        ..begin = _tween.evaluate(_animation)
        ..end = widget.decoration;

      _controller
        ..value = 0.0
        ..forward();
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        return DecoratedBox(
          decoration: _tween.animate(animation).value,
          child: child,
        );
      },
      child: widget.child,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}
